/* ******************************************************************************
 * Copyright (c) 2006-2013 XMind Ltd. and others.
 * 
 * This file is a part of XMind 3. XMind releases 3 and
 * above are dual-licensed under the Eclipse Public License (EPL),
 * which is available at http://www.eclipse.org/legal/epl-v10.html
 * and the GNU Lesser General Public License (LGPL), 
 * which is available at http://www.gnu.org/licenses/lgpl.html
 * See https://www.xmind.net/license.html for details.
 * 
 * Contributors:
 *     XMind Ltd. - initial API and implementation
 *******************************************************************************/
package org.xmind.ui.exports.vector.graphics;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Composite;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.util.Stack;

import org.eclipse.core.runtime.Platform;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.SWTGraphics;
import org.eclipse.draw2d.TextUtilities;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.LineAttributes;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.graphics.PathData;
import org.eclipse.swt.graphics.Pattern;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.widgets.Display;
import org.xmind.gef.draw2d.graphics.GradientPattern;

/**
 * @author Jason Wong
 */
public class GraphicsToGraphics2DAdaptor extends Graphics {
    private static class State {

        public int translateX = 0;

        public int translateY = 0;

        /**
         * clipping rectangle x coordinate
         */
        public int clipX = 0;
        /**
         * clipping rectangle y coordinate
         */
        public int clipY = 0;
        /**
         * clipping rectangle width
         */
        public int clipW = 0;
        /**
         * clipping rectangle height
         */
        public int clipH = 0;

        /** Font value **/
        /**
         * cached font
         */
        public Font font;

        /**
         * cached xor mode value
         */
        public boolean XorMode = false;
        /**
         * cached foreground color
         */
        public Color fgColor;
        /**
         * cached background color
         */
        public Color bgColor;
        /**
         * cached foreground color
         */
        public Pattern fgPattern;
        /**
         * cached background pattern
         */
        public Pattern bgPattern;

        /**
         * cached alpha value
         */
        public int alpha;

        /**
         * Line attributes value
         */
        public LineAttributes lineAttributes = new LineAttributes(1);

        int graphicHints;

        /**
         * Copy the values from a given state to this state
         * 
         * @param state
         *            the state to copy from
         */
        public void copyFrom(State state) {
            translateX = state.translateX;
            translateY = state.translateY;

            clipX = state.clipX;
            clipY = state.clipY;
            clipW = state.clipW;
            clipH = state.clipH;

            font = state.font;
            fgColor = state.fgColor;
            bgColor = state.bgColor;

            bgPattern = state.bgPattern;
            fgPattern = state.fgPattern;

            XorMode = state.XorMode;
            alpha = state.alpha;
            graphicHints = state.graphicHints;

            lineAttributes = SWTGraphics.clone(state.lineAttributes);
        }
    }

    static final int ADVANCED_GRAPHICS_MASK;
    static final int ADVANCED_SHIFT;
    static final int FILL_RULE_MASK;
    static final int FILL_RULE_SHIFT;
    static final int FILL_RULE_WHOLE_NUMBER = -1;

    /*
     * It's consistent with SWTGraphics flags in case some other flags from
     * SWTGraphics need to be here
     */
    static {
        FILL_RULE_SHIFT = 14;
        ADVANCED_SHIFT = 15;
        FILL_RULE_MASK = 1 << FILL_RULE_SHIFT; // If changed to more than 1-bit,
                                              // check references!
        ADVANCED_GRAPHICS_MASK = 1 << ADVANCED_SHIFT;
    }

    private SWTGraphics swtGraphics;
    private Graphics2D graphics2D;
    private BasicStroke stroke;
    private Stack<State> states = new Stack<State>();
    private final State currentState = new State();
    private final State appliedState = new State();

    private double[] flatMatrixState;

    /**
     * Some strings, Asian string in particular, are painted differently between
     * SWT and AWT. SWT falls back to some default locale font if Asian string
     * cannot be painted with the current font - this is done via the platform.
     * AWT, unlike platform biased SWT, does not. Hence, Asian string widths are
     * very different between SWT and AWT. To workaround the issue, if the flag
     * below is set to <code>true</code> then once SWT and AWT string width are
     * not equal, a bitmap of the SWT string will be painted. Otherwise the
     * string is always painted with AWT Graphics 2D string rendering.
     */
    protected boolean paintNotCompatibleStringsAsBitmaps = true;

    @SuppressWarnings("unused")
    private static final TextUtilities TEXT_UTILITIES = new TextUtilities();

    private Rectangle relativeClipRegion;

    private org.eclipse.swt.graphics.Rectangle viewBox;
    private Image image;

    /**
     * x coordinate for graphics translation
     */
    private int transX = 0;
    /**
     * y coordinate for graphics translation
     */
    private int transY = 0;

    /**
     * current rotation angle
     */
    private float angle;
    /**
     * The x coordinate of the rotation point
     */
    private int rotateX;
    /**
     * The y coordinate of the rotation point
     */
    private int rotateY;

    /**
     * horizontal scale
     */
    private float horizontalScale = 1.0f;

    /**
     * vertical scale
     */
    private float verticalScale = 1.0f;

    /**
     * Constructor
     * 
     * @param graphics
     *            the <code>Graphics2D</code> object that this object is
     *            delegating calls to.
     * @param viewPort
     *            the <code>Rectangle</code> that defines the logical area being
     *            rendered by the graphics object.
     */
    public GraphicsToGraphics2DAdaptor(Graphics2D graphics, Rectangle viewPort,
            Display display) {
        this(graphics, new org.eclipse.swt.graphics.Rectangle(viewPort.x,
                viewPort.y, viewPort.width, viewPort.height), display);
    }

    private Display display;

    private static int rotateOrientation = 0;

    /**
     * Alternate Constructor that takes an swt Rectangle
     * 
     * @param graphics
     *            the <code>Graphics2D</code> object that this object is
     *            delegating calls to.
     * @param viewPort
     *            the <code>org.eclipse.swt.graphics.Rectangle</code> that
     *            defines the logical area being rendered by the graphics
     *            object.
     */
    public GraphicsToGraphics2DAdaptor(Graphics2D graphics,
            org.eclipse.swt.graphics.Rectangle viewPort, Display display) {

        this.display = display;

        // Save the ViewPort to add to the root DOM element
        viewBox = viewPort;

        // Create the SWT Graphics Object
        createSWTGraphics();

        // Initialize the SVG Graphics Object
        initSVGGraphics(graphics);

        // Initialize the States
        init();
    }

    /**
     * This is a helper method used to create the SWT Graphics object
     */
    private void createSWTGraphics() {

        // we need this temp Rect just to instantiate an swt image in order to
        // keep
        // state, the size of this Rect is of no consequence and we just set it
        // to
        // such a small size in order to minimize memory allocation
        org.eclipse.swt.graphics.Rectangle tempRect = new org.eclipse.swt.graphics.Rectangle(
                0, 0, 10, 10);
        image = new Image(display, tempRect);
        GC gc = new GC(image);
        swtGraphics = new SWTGraphics(gc);
    }

    /**
     * Create the SVG graphics object and initializes it with the current line
     * style and width
     */
    private void initSVGGraphics(Graphics2D graphics) {
        this.graphics2D = graphics;

        relativeClipRegion = new Rectangle(viewBox.x, viewBox.y, viewBox.width,
                viewBox.height);

        // Initialize the line style and width
        stroke = new BasicStroke(swtGraphics.getLineWidth(),
                BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 0, null, 0);
        LineAttributes lineAttributes = new LineAttributes(1);
        swtGraphics.getLineAttributes(lineAttributes);
        setLineAttributes(lineAttributes);
        setFillRule(swtGraphics.getFillRule());
        setAdvanced(swtGraphics.getAdvanced());
        getGraphics2D().setStroke(stroke);
    }

    /**
     * This method should only be called by the constructor. Initializes state
     * information for the currentState
     */
    private void init() {

        // Initialize drawing styles
        setForegroundColor(getForegroundColor());
        setBackgroundColor(getBackgroundColor());
        setXORMode(getXORMode());

        // Initialize Font
        setFont(getFont());
        currentState.font = appliedState.font = getFont();

        // Initialize translations
        currentState.translateX = appliedState.translateX = transX;
        currentState.translateY = appliedState.translateY = transY;

        // Initialize Clip Regions
        currentState.clipX = appliedState.clipX = relativeClipRegion.x;
        currentState.clipY = appliedState.clipY = relativeClipRegion.y;
        currentState.clipW = appliedState.clipW = relativeClipRegion.width;
        currentState.clipH = appliedState.clipH = relativeClipRegion.height;

        currentState.alpha = appliedState.alpha = getAlpha();
    }

    /**
     * Verifies that the applied state is up to date with the current state and
     * updates the applied state accordingly.
     */
    protected void checkState() {
        if (appliedState.font != currentState.font) {
            appliedState.font = currentState.font;

            setFont(currentState.font);
        }

        if (appliedState.clipX != currentState.clipX
                || appliedState.clipY != currentState.clipY
                || appliedState.clipW != currentState.clipW
                || appliedState.clipH != currentState.clipH) {

            appliedState.clipX = currentState.clipX;
            appliedState.clipY = currentState.clipY;
            appliedState.clipW = currentState.clipW;
            appliedState.clipH = currentState.clipH;

            if (rotateOrientation != 0) {
                if (currentState.bgColor.equals(currentState.fgColor)) {
                    double p = Math.pow(currentState.clipW, 2)
                            + Math.pow(currentState.clipH, 2);
                    int newWidth = Math.round((float) Math.sqrt(p));
                    currentState.clipX = currentState.clipX
                            - (newWidth - currentState.clipW) / 2;
                    currentState.clipW = newWidth;
                }
            }

            // Adjust the clip for SVG
            getGraphics2D().setClip(currentState.clipX - 1,
                    currentState.clipY - 1, currentState.clipW + 2,
                    currentState.clipH + 2);
        }

        if (appliedState.alpha != currentState.alpha) {
            appliedState.alpha = currentState.alpha;

            setAlpha(currentState.alpha);
        }

        appliedState.graphicHints = currentState.graphicHints;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#clipRect(org.eclipse.draw2d.geometry.
     * Rectangle )
     */
    @Override
    public void clipRect(Rectangle rect) {
        relativeClipRegion.intersect(rect);
        setClipAbsolute(relativeClipRegion.x + transX,
                relativeClipRegion.y + transY, relativeClipRegion.width,
                relativeClipRegion.height);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#dispose()
     */
    @Override
    public void dispose() {
        rotateOrientation = 0;
        swtGraphics.dispose();

        if (image != null) {
            image.dispose();
        }

        states.clear();
    }

    /**
     * This method is used to convert an SWT Color to an AWT Color.
     * 
     * @param toConvert
     *            SWT Color to convert
     * @return AWT Color
     */
    protected java.awt.Color getColor(Color toConvert) {

        return new java.awt.Color(toConvert.getRed(), toConvert.getGreen(),
                toConvert.getBlue(), getAlpha());
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawArc(int, int, int, int, int, int)
     */
    @Override
    public void drawArc(int x, int y, int width, int height, int startAngle,
            int endAngle) {

        Arc2D arc = new Arc2D.Float(x + transX, y + transY, width - 1, height,
                startAngle, endAngle, Arc2D.OPEN);

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getForegroundColor()));
        getGraphics2D().setStroke(createStroke());
        getGraphics2D().draw(arc);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#fillArc(int, int, int, int, int, int)
     */
    @Override
    public void fillArc(int x, int y, int w, int h, int offset, int length) {

        Arc2D arc = new Arc2D.Float(x + transX, y + transY, w, h, offset,
                length, Arc2D.OPEN);

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getBackgroundColor()));
        getGraphics2D().fill(arc);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawFocus(int, int, int, int)
     */
    @Override
    public void drawFocus(int x, int y, int w, int h) {
        drawRectangle(x, y, w, h);
    }

    @Override
    public void drawTextLayout(TextLayout layout, int x, int y,
            int selectionStart, int selectionEnd, Color selectionForeground,
            Color selectionBackground) {
        checkState();
        if (!layout.getBounds().isEmpty()) {
            Image image = new Image(display, layout.getBounds().width,
                    layout.getBounds().height);
            GC gc = new GC(image);
            cloneGC(gc);
            layout.draw(gc, 0, 0, selectionStart, selectionEnd,
                    selectionForeground, selectionBackground);

            ImageData imageData = image.getImageData();
            imageData.transparentPixel = imageData.palette
                    .getPixel(getBackgroundColor().getRGB());

            gc.dispose();
            image.dispose();

            getGraphics2D().drawImage(
                    ImageConverter.convertFromImageData(imageData), x + transX,
                    y + transY, null);
        }
    }

    private void cloneGC(GC gc) {
        gc.setAdvanced(getAdvanced());
        gc.setAlpha(getAlpha());
        gc.setAntialias(getAntialias());
        gc.setFillRule(getFillRule());
        gc.setFont(getFont());
        gc.setInterpolation(getInterpolation());
        gc.setLineAttributes(getLineAttributes());
        gc.setTextAntialias(getTextAntialias());
        gc.setBackground(getBackgroundColor());
        gc.setForeground(getForegroundColor());
    }

    @Override
    public int getInterpolation() {
        return swtGraphics.getInterpolation();
    }

    @Override
    public LineAttributes getLineAttributes() {
        LineAttributes la = new LineAttributes(1);
        swtGraphics.getLineAttributes(la);
        return la;
    }

    @Override
    public int getTextAntialias() {
        return swtGraphics.getTextAntialias();
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.draw2d.Graphics#drawImage(org.eclipse.swt.graphics.Image,
     * int, int)
     */
    @Override
    public void drawImage(Image srcImage, int xpos, int ypos) {

        // Translate the Coordinates
        xpos += transX;
        ypos += transY;

        // Convert the SWT Image into an AWT BufferedImage
        BufferedImage toDraw = ImageConverter.convert(srcImage);

        checkState();
        getGraphics2D().drawImage(toDraw,
                new AffineTransform(1f, 0f, 0f, 1f, xpos, ypos), null);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.draw2d.Graphics#drawImage(org.eclipse.swt.graphics.Image,
     * int, int, int, int, int, int, int, int)
     */
    @Override
    public void drawImage(Image srcImage, int x1, int y1, int w1, int h1,
            int x2, int y2, int w2, int h2) {

        x2 += transX;
        y2 += transY;

        BufferedImage toDraw = ImageConverter.convert(srcImage);
        checkState();
        getGraphics2D().drawImage(toDraw, x2, y2, w2, h2, null);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawLine(int, int, int, int)
     */
    @Override
    public void drawLine(int x1, int y1, int x2, int y2) {

        Line2D line = new Line2D.Float(x1 + transX, y1 + transY, x2 + transX,
                y2 + transY);

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getForegroundColor()));
        getGraphics2D().setStroke(createStroke());
        getGraphics2D().draw(line);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawOval(int, int, int, int)
     */
    @Override
    public void drawOval(int x, int y, int w, int h) {

        Ellipse2D ellipse = new Ellipse2D.Float(x + transX, y + transY, w, h);

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getForegroundColor()));
        getGraphics2D().setStroke(createStroke());
        getGraphics2D().draw(ellipse);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#fillOval(int, int, int, int)
     */
    @Override
    public void fillOval(int x, int y, int w, int h) {

        Ellipse2D ellipse = new Ellipse2D.Float(x + transX, y + transY, w - 1,
                h - 1);

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getBackgroundColor()));
        getGraphics2D().fill(ellipse);
    }

    private Polygon createPolygon(PointList pointList) {

        Polygon toCreate = new Polygon();

        for (int i = 0; i < pointList.size(); i++) {
            Point pt = pointList.getPoint(i);

            toCreate.addPoint(pt.x + transX, pt.y + transY);
        }

        return toCreate;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawPolygon(org.eclipse.draw2d.geometry.
     * PointList )
     */
    @Override
    public void drawPolygon(PointList pointList) {
        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getForegroundColor()));
        getGraphics2D().setStroke(createStroke());
        getGraphics2D().draw(createPolygon(pointList));
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#fillPolygon(org.eclipse.draw2d.geometry.
     * PointList )
     */
    @Override
    public void fillPolygon(PointList pointList) {

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getBackgroundColor()));
        getGraphics2D().fill(createPolygon(pointList));
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.draw2d.Graphics#drawPolyline(org.eclipse.draw2d.geometry.
     * PointList)
     */
    @Override
    public void drawPolyline(PointList pointList) {

        // Draw polylines as a series of lines
        for (int x = 1; x < pointList.size(); x++) {

            Point p1 = pointList.getPoint(x - 1);
            Point p2 = pointList.getPoint(x);

            drawLine(p1.x, p1.y, p2.x, p2.y);
        }
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawRectangle(int, int, int, int)
     */
    @Override
    public void drawRectangle(int x, int y, int w, int h) {
        Rectangle2D rect = new Rectangle2D.Float(x + transX, y + transY, w, h);

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getForegroundColor()));

        getGraphics2D().setStroke(createStroke());
        getGraphics2D().draw(rect);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#fillRectangle(int, int, int, int)
     */
    @Override
    public void fillRectangle(int x, int y, int width, int height) {

        Rectangle2D rect = new Rectangle2D.Float(x + transX, y + transY, width,
                height);

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getBackgroundColor()));
        getGraphics2D().fill(rect);
    }

    public void fillRectangle(int width, int height, Color bgColor) {
        Rectangle2D rect = new Rectangle2D.Float(0, 0, width, height);
        checkState();
        getGraphics2D().setPaint(getColor(bgColor));
        getGraphics2D().fill(rect);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawRoundRectangle(org.eclipse.draw2d.
     * geometry .Rectangle, int, int)
     */
    @Override
    public void drawRoundRectangle(Rectangle rect, int arcWidth,
            int arcHeight) {

        RoundRectangle2D roundRect = new RoundRectangle2D.Float(rect.x + transX,
                rect.y + transY, rect.width, rect.height, arcWidth, arcHeight);

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getForegroundColor()));
        getGraphics2D().setStroke(createStroke());
        getGraphics2D().draw(roundRect);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#fillRoundRectangle(org.eclipse.draw2d.
     * geometry .Rectangle, int, int)
     */
    @Override
    public void fillRoundRectangle(Rectangle rect, int arcWidth,
            int arcHeight) {

        RoundRectangle2D roundRect = new RoundRectangle2D.Float(rect.x + transX,
                rect.y + transY, rect.width, rect.height, arcWidth, arcHeight);

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getBackgroundColor()));
        getGraphics2D().fill(roundRect);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawText(java.lang.String, int, int)
     */
    @Override
    public void drawText(String s, int x, int y) {
        drawString(s, x, y);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawString(java.lang.String, int, int)
     */

    // private static Dimension swtStringSize;

    @Override
    public void drawString(String s, int x, int y) {
        if (s == null)
            return;
        java.awt.FontMetrics metrics = getGraphics2D().getFontMetrics();
        int stringLength = metrics.stringWidth(s);
        // if (!this.display.isDisposed()) {
        // Runnable runnable = new Runnable() {
        // public void run() {
        // swtStringSize = TEXT_UTILITIES.getStringExtents(str,
        // swtGraphics.getFont());
        // }
        // };
        // display.syncExec(runnable);
        // }

        float xpos = x + transX;
        float ypos = y + transY;
        int lineWidth;

        // if (paintNotCompatibleStringsAsBitmaps
        // && Math.abs(swtStringSize.width - stringLength) > 2) {
        // // create SWT bitmap of the string then
        // Image image = new Image(display, swtStringSize.width + 1,
        // swtStringSize.height + 1);
        // GC gc = new GC(image);
        // gc.setForeground(getForegroundColor());
        // gc.setBackground(getBackgroundColor());
        // gc.setAntialias(getAntialias());
        // gc.setFont(getFont());
        // gc.drawString(s, 0, 0);
        // gc.dispose();
        // ImageData data = image.getImageData();
        // image.dispose();
        // RGB backgroundRGB = getBackgroundColor().getRGB();
        // for (int i = 0; i < data.width; i++) {
        // for (int j = 0; j < data.height; j++) {
        // if (data.palette.getRGB(data.getPixel(i, j)).equals(
        // backgroundRGB)) {
        // data.setAlpha(i, j, 0);
        // } else {
        // data.setAlpha(i, j, 255);
        // }
        // }
        // }
        // getGraphics2D().drawImage(
        // ImageConverter.convertFromImageData(data),
        // new AffineTransform(1f, 0f, 0f, 1f, xpos, ypos), null);
        // stringLength = swtStringSize.width;
        // } else {

        ypos += metrics.getAscent();

        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getForegroundColor()));
        getGraphics2D().drawString(s, xpos, ypos);
        if (Platform.OS_LINUX.equals(Platform.getOS()))
            swtGraphics.drawString(s, (int) xpos, (int) ypos);
        // }

        if (isFontUnderlined(getFont())) {
            int baseline = y + metrics.getAscent();
            lineWidth = getLineWidth();

            setLineWidth(1);
            drawLine(x, baseline, x + stringLength, baseline);
            setLineWidth(lineWidth);
        }

        if (isFontStrikeout(getFont())) {
            int strikeline = y + (metrics.getHeight() / 2);
            lineWidth = getLineWidth();

            setLineWidth(1);
            drawLine(x, strikeline, x + stringLength, strikeline);
            setLineWidth(lineWidth);
        }

    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#fillString(java.lang.String, int, int)
     */
    @Override
    public void fillString(String s, int x, int y) {
        // Not implemented
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#fillText(java.lang.String, int, int)
     */
    @Override
    public void fillText(String s, int x, int y) {
        // Not implemented
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#getBackgroundColor()
     */
    @Override
    public Color getBackgroundColor() {
        return swtGraphics.getBackgroundColor();
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.draw2d.Graphics#getClip(org.eclipse.draw2d.geometry.Rectangle
     * )
     */
    @Override
    public Rectangle getClip(Rectangle rect) {
        rect.setBounds(relativeClipRegion);
        return rect;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#getFont()
     */
    @Override
    public Font getFont() {
        return swtGraphics.getFont();
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#getFontMetrics()
     */
    @Override
    public FontMetrics getFontMetrics() {
        return swtGraphics.getFontMetrics();
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#getForegroundColor()
     */
    @Override
    public Color getForegroundColor() {
        return swtGraphics.getForegroundColor();
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#getLineStyle()
     */
    @Override
    public int getLineStyle() {
        return swtGraphics.getLineStyle();
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#getLineWidth()
     */
    @Override
    public int getLineWidth() {
        return swtGraphics.getLineWidth();
    }

    @Override
    public float getLineWidthFloat() {
        return swtGraphics.getLineWidthFloat();
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#getXORMode()
     */
    @Override
    public boolean getXORMode() {
        return swtGraphics.getXORMode();
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#popState()
     */
    @Override
    public void popState() {
        swtGraphics.popState();

        restoreState(states.pop());
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#pushState()
     */
    @Override
    public void pushState() {
        swtGraphics.pushState();
//        if (angle != 0) {
//            getGraphics2D().rotate(Math.toRadians(360 - angle), rotateX,
//                    rotateY);
//            angle = 0;
//        }
        flatMatrixState = new double[6];
        getGraphics2D().getTransform().getMatrix(flatMatrixState);

        // Make a copy of the current state and push it onto the stack
        State toPush = new State();
        toPush.copyFrom(currentState);
        states.push(toPush);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#restoreState()
     */
    @Override
    public void restoreState() {
        swtGraphics.restoreState();

        restoreState(states.peek());
    }

    private void restoreState(State state) {

        setBackgroundColor(state.bgColor);
        setForegroundColor(state.fgColor);

        setBackgroundPattern(state.bgPattern);
        setForegroundPattern(state.fgPattern);

        setLineAttributes(state.lineAttributes);
        setXORMode(state.XorMode);

        setClipAbsolute(state.clipX, state.clipY, state.clipW, state.clipH);

        transX = currentState.translateX = state.translateX;
        transY = currentState.translateY = state.translateY;

        relativeClipRegion.x = state.clipX - transX;
        relativeClipRegion.y = state.clipY - transY;
        relativeClipRegion.width = state.clipW;
        relativeClipRegion.height = state.clipH;

        currentState.font = state.font;
        currentState.alpha = state.alpha;

        if (flatMatrixState != null) {
            getGraphics2D().setTransform(new AffineTransform(flatMatrixState));
        }
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#scale(double)
     */
    @Override
    public void scale(double amount) {
        scale((float) amount, (float) amount);
    }

    @Override
    public void scale(float horizontal, float vertical) {
        if (horizontal == -1 || vertical == -1) {
            horizontalScale *= horizontal;
            verticalScale *= vertical;
        } else {
            horizontalScale = horizontal;
            verticalScale = vertical;
        }
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.draw2d.Graphics#setBackgroundColor(org.eclipse.swt.graphics
     * .Color)
     */
    @Override
    public void setBackgroundColor(Color rgb) {
        currentState.bgColor = rgb;
        swtGraphics.setBackgroundColor(rgb);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.draw2d.Graphics#setClip(org.eclipse.draw2d.geometry.Rectangle
     * )
     */
    @Override
    public void setClip(Rectangle rect) {
        relativeClipRegion.x = rect.x;
        relativeClipRegion.y = rect.y;
        relativeClipRegion.width = rect.width;
        relativeClipRegion.height = rect.height;

        setClipAbsolute(rect.x + transX, rect.y + transY, rect.width,
                rect.height);
    }

    /**
     * Sets the current clip values
     * 
     * @param x
     *            the x value
     * @param y
     *            the y value
     * @param width
     *            the width value
     * @param height
     *            the height value
     */
    private void setClipAbsolute(int x, int y, int width, int height) {
        currentState.clipX = x;
        currentState.clipY = y;
        currentState.clipW = width;
        currentState.clipH = height;
    }

    private boolean isFontUnderlined(Font f) {
        return false;
    }

    private boolean isFontStrikeout(Font f) {
        return false;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#setFont(org.eclipse.swt.graphics.Font)
     */
    @Override
    public void setFont(Font f) {
        swtGraphics.setFont(f);
        currentState.font = f;

        FontData[] fontInfo = f.getFontData();

        if (fontInfo[0] != null) {

            int height = fontInfo[0].getHeight();

            // float fsize = height * (float) display.getDPI().x / 72.0f;
            float fsize = height * 72.0f / 72.0f;
            height = Math.round(fsize);

            int style = fontInfo[0].getStyle();
            boolean bItalic = (style & SWT.ITALIC) == SWT.ITALIC;
            boolean bBold = (style & SWT.BOLD) == SWT.BOLD;
            String faceName = fontInfo[0].getName();
            int escapement = 0;

            boolean bUnderline = isFontUnderlined(f);
            boolean bStrikeout = isFontStrikeout(f);

            GdiFont font = new GdiFont(height, bItalic, bUnderline, bStrikeout,
                    bBold, faceName, escapement);

            getGraphics2D().setFont(font.getFont());
        }
    }

    /*
     * (non-Javadoc)
     * @see
     * org.eclipse.draw2d.Graphics#setForegroundColor(org.eclipse.swt.graphics
     * .Color)
     */
    @Override
    public void setForegroundColor(Color rgb) {
        currentState.fgColor = rgb;
        swtGraphics.setForegroundColor(rgb);
    }

    /**
     * Sets the dash pattern when the custom line style is in use. Because this
     * feature is rarely used, the dash pattern may not be preserved when
     * calling {@link #pushState()} and {@link #popState()}.
     * 
     * @param dash
     *            the pixel pattern
     */
    @Override
    public void setLineDash(int[] dash) {
        float dashFlt[] = new float[dash.length];
        for (int i = 0; i < dash.length; i++) {
            dashFlt[i] = dash[i];
        }
        setLineDash(dashFlt);
    }

    @Override
    public void setLineDash(float[] dash) {
        currentState.lineAttributes.dash = dash;
        setLineStyle(SWTGraphics.LINE_CUSTOM);
        swtGraphics.setLineDash(dash);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#setLineStyle(int)
     */
    @Override
    public void setLineStyle(int style) {
        currentState.lineAttributes.style = style;
        swtGraphics.setLineStyle(style);
    }

    /**
     * ignored
     */
    @Override
    public void setLineMiterLimit(float miterLimit) {
        // do nothing
        swtGraphics.setLineMiterLimit(miterLimit);
    }

    /**
     * ignored
     */
    @Override
    public void setLineCap(int cap) {
        // do nothing
    }

    /**
     * ignored
     */
    @Override
    public void setLineJoin(int join) {
        // do nothing
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#setLineWidth(int)
     */
    @Override
    public void setLineWidth(int width) {
        setLineWidthFloat(width);
    }

    @Override
    public void setLineWidthFloat(float width) {
        currentState.lineAttributes.width = width;
        swtGraphics.setLineWidthFloat(width);
    }

    @Override
    public void setLineAttributes(LineAttributes lineAttributes) {
        SWTGraphics.copyLineAttributes(currentState.lineAttributes,
                lineAttributes);
        swtGraphics.setLineAttributes(lineAttributes);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#setXORMode(boolean)
     */
    @Override
    public void setXORMode(boolean xorMode) {
        currentState.XorMode = xorMode;
        swtGraphics.setXORMode(xorMode);
    }

    /**
     * Sets the current translation values
     * 
     * @param x
     *            the x translation value
     * @param y
     *            the y translation value
     */
    private void setTranslation(int x, int y) {
        transX = currentState.translateX = x;
        transY = currentState.translateY = y;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#translate(int, int)
     */
    @Override
    public void translate(int dx, int dy) {
        swtGraphics.translate(dx, dy);

        setTranslation(transX + dx, transY + dy);
        relativeClipRegion.x -= dx;
        relativeClipRegion.y -= dy;
    }

    @Override
    public void translate(float dx, float dy) {
        dx *= horizontalScale;
        dy *= verticalScale;
        swtGraphics.translate(dx, dy);

        setTranslation(transX + (int) dx, transY + (int) dy);
        relativeClipRegion.x -= dx;
        relativeClipRegion.y -= dy;
    }

    /**
     * @return the <code>Graphics2D</code> that this is delegating to.
     */
    protected Graphics2D getGraphics2D() {
        return graphics2D;
    }

    /**
     * @return Returns the swtGraphics.
     */
    private SWTGraphics getSWTGraphics() {
        return swtGraphics;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#fillGradient(int, int, int, int,
     * boolean)
     */
    @Override
    public void fillGradient(int x, int y, int w, int h, boolean vertical) {
        GradientPaint gradient;

        checkState();

        // Gradients in SWT start with Foreground Color and end at Background
        java.awt.Color start = getColor(getSWTGraphics().getForegroundColor());
        java.awt.Color stop = getColor(getSWTGraphics().getBackgroundColor());

        // Create the Gradient based on horizontal or vertical
        if (vertical) {
            gradient = new GradientPaint(x + transX, y + transY, start,
                    x + transX, y + h + transY, stop);
        } else {
            gradient = new GradientPaint(x + transX, y + transY, start,
                    x + w + transX, y + transY, stop);
        }

        Paint oldPaint = getGraphics2D().getPaint();
        getGraphics2D().setPaint(gradient);
        getGraphics2D()
                .fill(new Rectangle2D.Double(x + transX, y + transY, w, h));
        getGraphics2D().setPaint(oldPaint);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#drawPath(org.eclipse.swt.graphics.Path)
     */
    @Override
    public void drawPath(Path path) {
        GeneralPath pathAWT = createPathAWT(path);
        // getGraphics2D().draw(pathAWT);
        checkState();
        getGraphics2D().setPaint(getColor(swtGraphics.getForegroundColor()));
        getGraphics2D().setStroke(createStroke());
        getGraphics2D().draw(pathAWT);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#fillPath(org.eclipse.swt.graphics.Path)
     */
    @Override
    public void fillPath(Path path) {
        checkState();
        if (currentState.bgPattern == null
                || !(currentState.bgPattern instanceof GradientPattern)) {
            getGraphics2D()
                    .setPaint(getColor(swtGraphics.getBackgroundColor()));
        } else {
            GradientPattern gp = (GradientPattern) currentState.bgPattern;
            getGraphics2D().setPaint(getColor(gp.color2));
        }
        getGraphics2D().fill(createPathAWT(path));
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#setClip(org.eclipse.swt.graphics.Path)
     */
    @Override
    public void setClip(Path path) {
        if (((appliedState.graphicHints ^ currentState.graphicHints)
                & FILL_RULE_MASK) != 0) {
            // If there is a pending change to the fill rule, apply it first.
            // As long as the FILL_RULE is stored in a single bit, just toggling
            // it works.
            appliedState.graphicHints ^= FILL_RULE_MASK;
        }
        getGraphics2D().setClip(createPathAWT(path));
        appliedState.clipX = currentState.clipX = 0;
        appliedState.clipY = currentState.clipY = 0;
        appliedState.clipW = currentState.clipW = 0;
        appliedState.clipH = currentState.clipH = 0;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#getFillRule()
     */
    @Override
    public int getFillRule() {
        return ((currentState.graphicHints & FILL_RULE_MASK) >> FILL_RULE_SHIFT)
                - FILL_RULE_WHOLE_NUMBER;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#setFillRule(int)
     */
    @Override
    public void setFillRule(int rule) {
        currentState.graphicHints &= ~FILL_RULE_MASK;
        currentState.graphicHints |= (rule
                + FILL_RULE_WHOLE_NUMBER) << FILL_RULE_SHIFT;
    }

    private GeneralPath createPathAWT(Path path) {
        GeneralPath pathAWT = new GeneralPath();
        PathData pathData = path.getPathData();
        int idx = 0;
        for (int i = 0; i < pathData.types.length; i++) {
            switch (pathData.types[i]) {
            case SWT.PATH_MOVE_TO:
                pathAWT.moveTo(
                        pathData.points[idx++] * horizontalScale + transX,
                        pathData.points[idx++] * verticalScale + transY);
                break;
            case SWT.PATH_LINE_TO:
                pathAWT.lineTo(
                        pathData.points[idx++] * horizontalScale + transX,
                        pathData.points[idx++] * verticalScale + transY);
                break;
            case SWT.PATH_CUBIC_TO:
                pathAWT.curveTo(
                        pathData.points[idx++] * horizontalScale + transX,
                        pathData.points[idx++] * verticalScale + transY,
                        pathData.points[idx++] * horizontalScale + transX,
                        pathData.points[idx++] * verticalScale + transY,
                        pathData.points[idx++] * horizontalScale + transX,
                        pathData.points[idx++] * verticalScale + transY);
                break;
            case SWT.PATH_QUAD_TO:
                pathAWT.quadTo(
                        pathData.points[idx++] * horizontalScale + transX,
                        pathData.points[idx++] * verticalScale + transY,
                        pathData.points[idx++] * horizontalScale + transX,
                        pathData.points[idx++] * verticalScale + transY);
                break;
            case SWT.PATH_CLOSE:
                pathAWT.closePath();
                break;
            default:
                dispose();
                SWT.error(SWT.ERROR_INVALID_ARGUMENT);
            }
        }
        int swtWindingRule = ((appliedState.graphicHints
                & FILL_RULE_MASK) >> FILL_RULE_SHIFT) - FILL_RULE_WHOLE_NUMBER;
        if (swtWindingRule == SWT.FILL_WINDING) {
            pathAWT.setWindingRule(GeneralPath.WIND_NON_ZERO);
        } else if (swtWindingRule == SWT.FILL_EVEN_ODD) {
            pathAWT.setWindingRule(GeneralPath.WIND_EVEN_ODD);
        } else {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }
        return pathAWT;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.gmf.runtime.draw2d.ui.render.awt.internal.
     * DrawableRenderedImage #allowDelayRender()
     */
    public boolean shouldAllowDelayRender() {
        return false;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.gmf.runtime.draw2d.ui.render.awt.internal.
     * DrawableRenderedImage #getMaximumRenderSize()
     */
    public Dimension getMaximumRenderSize() {
        return null;
    }

    /**
     * Accessor method to return the translation offset for the graphics object
     * 
     * @return <code>Point</code> x coordinate for graphics translation
     */
    protected Point getTranslationOffset() {
        return new Point(transX, transY);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#getAntialias()
     */
    @Override
    public int getAntialias() {
        Object antiAlias = getGraphics2D()
                .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
        if (antiAlias != null) {
            if (antiAlias.equals(RenderingHints.VALUE_ANTIALIAS_ON))
                return SWT.ON;
            else if (antiAlias.equals(RenderingHints.VALUE_ANTIALIAS_OFF))
                return SWT.OFF;
            else if (antiAlias.equals(RenderingHints.VALUE_ANTIALIAS_DEFAULT))
                return SWT.DEFAULT;
        }

        return SWT.DEFAULT;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.draw2d.Graphics#setAntialias(int)
     */
    @Override
    public void setAntialias(int value) {
        if (value == SWT.ON) {
            getGraphics2D().setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
        } else if (value == SWT.OFF) {
            getGraphics2D().setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_OFF);
        }
        setAdvanced(true);
    }

    @Override
    public int getAlpha() {
        return swtGraphics.getAlpha();
    }

    @Override
    public void setAlpha(int alpha) {
        alpha = Math.min(255, alpha);
        swtGraphics.setAlpha(alpha);
        currentState.alpha = alpha;

        Composite composite = getGraphics2D().getComposite();
        if (composite instanceof AlphaComposite) {
            AlphaComposite newComposite = AlphaComposite.getInstance(
                    ((AlphaComposite) composite).getRule(),
                    (float) alpha / (float) 255);
            getGraphics2D().setComposite(newComposite);
        }
    }

    protected BasicStroke getStroke() {
        return stroke;
    }

    protected void setStroke(BasicStroke stroke) {
        this.stroke = stroke;
        getGraphics2D().setStroke(stroke);
    }

    /**
     * Sets and retirns AWT Stroke based on the value of
     * <code>LineAttributes</code> within the current state object
     * 
     * @return the new AWT stroke
     */
    private Stroke createStroke() {
        float factor = currentState.lineAttributes.width > 0
                ? currentState.lineAttributes.width : 3;
        float awt_dash[];
        int awt_cap;
        int awt_join;

        switch (currentState.lineAttributes.style) {
        case SWTGraphics.LINE_DASH:
            awt_dash = new float[] { factor * 6, factor * 3 };
            break;
        case SWTGraphics.LINE_DASHDOT:
            awt_dash = new float[] { factor * 3, factor, factor, factor };
            break;
        case SWTGraphics.LINE_DASHDOTDOT:
            awt_dash = new float[] { factor * 3, factor, factor, factor, factor,
                    factor };
            break;
        case SWTGraphics.LINE_DOT:
            awt_dash = new float[] { factor, factor };
            break;
        case SWTGraphics.LINE_CUSTOM:
            awt_dash = currentState.lineAttributes.dash;
            break;
        default:
            awt_dash = null;
        }

        switch (currentState.lineAttributes.cap) {
        case SWT.CAP_FLAT:
            awt_cap = BasicStroke.CAP_BUTT;
            break;
        case SWT.CAP_ROUND:
            awt_cap = BasicStroke.CAP_ROUND;
            break;
        case SWT.CAP_SQUARE:
            awt_cap = BasicStroke.CAP_SQUARE;
            break;
        default:
            awt_cap = BasicStroke.CAP_BUTT;
        }

        switch (currentState.lineAttributes.join) {
        case SWT.JOIN_BEVEL:
            awt_join = BasicStroke.JOIN_BEVEL;
            break;
        case SWT.JOIN_MITER:
            awt_join = BasicStroke.JOIN_MITER;
            break;
        case SWT.JOIN_ROUND:
            awt_join = BasicStroke.JOIN_ROUND;
        default:
            awt_join = BasicStroke.JOIN_MITER;
        }

        /*
         * SWT paints line width == 0 as if it is == 1, so AWT is synced up with
         * that below.
         */
        stroke = new BasicStroke(
                currentState.lineAttributes.width != 0
                        ? currentState.lineAttributes.width : 1,
                awt_cap, awt_join, currentState.lineAttributes.miterLimit,
                awt_dash, currentState.lineAttributes.dashOffset);
        return stroke;
    }

    @Override
    public boolean getAdvanced() {
        return (currentState.graphicHints & ADVANCED_GRAPHICS_MASK) != 0;
    }

    @Override
    public void setAdvanced(boolean value) {
        if (value) {
            currentState.graphicHints |= ADVANCED_GRAPHICS_MASK;
        } else {
            currentState.graphicHints &= ~ADVANCED_GRAPHICS_MASK;
        }
    }

    @Override
    public void clipPath(Path path) {
        if (((appliedState.graphicHints ^ currentState.graphicHints)
                & FILL_RULE_MASK) != 0) {
            // If there is a pending change to the fill rule, apply it first.
            // As long as the FILL_RULE is stored in a single bit, just toggling
            // it works.
            appliedState.graphicHints ^= FILL_RULE_MASK;
        }
        setClip(path);
        getGraphics2D().clipRect(relativeClipRegion.x + transX,
                relativeClipRegion.y + transY, relativeClipRegion.width,
                relativeClipRegion.height);
        java.awt.Rectangle bounds = getGraphics2D().getClip().getBounds();
        relativeClipRegion = new Rectangle(bounds.x, bounds.y, bounds.width,
                bounds.height);
    }

    @Override
    public void rotate(float degrees) {
        if (rotateOrientation == 0) {
            if (degrees > 0)
                rotateOrientation = 1;
            else if (degrees < 0)
                rotateOrientation = -1;
        }

        /*
         * Method was introduced to fix Bug 368146. With this at place no
         * exceptions happens during SVG export (which happened as soon as a
         * rotatable object like an ellipse is contained in the diagram), but
         * the object is still not rotated in the exported SVG graphics.
         */
        if (swtGraphics.getAdvanced()) {
            swtGraphics.rotate(degrees);
        }
        /*
         * The rotation has to be forwarded to the SVG Graphics object. This
         * rotation is stateful, all drawing actions thereafter will be rotated.
         * Thus the rotation coordinates have to be remembered and the rotation
         * needs to be inverted before the next object is drawn. The inverted
         * rotation is hence triggered in pushState(). Fix for Bug 369241
         */
        rotateDetail(degrees);
        if (this.angle == 0.0) {
            rotateOrientation = 0 - rotateOrientation;
            rotateDetail(degrees);
        }
    }

    private void rotateDetail(float degrees) {
        if ((rotateOrientation == 1 && degrees > 0)
                || (rotateOrientation == -1 && degrees < 0)) {
            getGraphics2D().rotate(Math.toRadians(degrees),
                    currentState.translateX, currentState.translateY);
            this.angle = degrees;
            this.rotateX = currentState.translateX;
            this.rotateY = currentState.translateY;
        }
    }

    @Override
    public int getLineCap() {
        return SWT.CAP_FLAT;
    }

    @Override
    public int getLineJoin() {
        return SWT.JOIN_MITER;
    }

    @Override
    public float getLineMiterLimit() {
        return 0;
    }

    @Override
    public void setBackgroundPattern(Pattern pattern) {
        currentState.bgPattern = pattern;
    }

    @Override
    public void setForegroundPattern(Pattern pattern) {
        currentState.fgPattern = pattern;
    }

    @Override
    public void setInterpolation(int interpolation) {
        // do nothing
    }

    @Override
    public void setLineDashOffset(float value) {
        // do nothing
    }

    @Override
    public void setTextAntialias(int value) {
        // do nothing
    }

    @Override
    public void shear(float horz, float vert) {
        // do nothing
    }

}
